/*!
 * \file SpinMutex.hpp
 * \brief 自旋锁实现，提供高性能的同步原语
 * 
 * \details 自旋锁是一种轻量级的同步机制，适用于短时间的临界区保护。
 *          与传统互斥锁不同，自旋锁在等待时不会让线程休眠，
 *          而是持续检查锁的状态，因此CPU开销较大但延迟更低。
 *          适用于高频交易等对延迟敏感的场景。
 */
#pragma once
#include <atomic>
#include <thread>
#ifdef _MSC_VER
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

/*!
 * \brief 自旋锁互斥量类
 * 
 * \details 基于std::atomic实现的高性能自旋锁，特点：
 *          - 使用原子操作保证线程安全
 *          - 在等待时主动让出CPU时间片
 *          - 支持多平台CPU指令优化
 *          - 适用于短时间临界区保护
 *          
 *          与std::mutex相比：
 *          - 优势：延迟更低，无系统调用开销
 *          - 劣势：CPU占用高，不适合长时间等待
 */
class SpinMutex
{
private:
	/// 原子标志位，false表示未锁定，true表示已锁定
	std::atomic<bool> flag = { false };

public:
	/*!
	 * \brief 获取锁
	 * 
	 * \details 使用自旋方式等待获取锁：
	 *          1. 尝试原子交换标志位
	 *          2. 如果获取失败，进入自旋等待
	 *          3. 在等待过程中使用CPU指令优化
	 *          4. 根据不同平台使用相应的暂停指令
	 */
	void lock()
	{
		for (;;)
		{
			// 尝试原子交换，如果成功获取锁则退出
			if (!flag.exchange(true, std::memory_order_acquire))
				break;

			// 自旋等待，检查锁是否被释放
			while (flag.load(std::memory_order_relaxed))
			{
#ifdef _MSC_VER
				// Windows平台：使用_mm_pause指令减少功耗
				_mm_pause();
#elif defined(__x86_64__) || defined(__i386__)
				// x86/x64平台：使用pause指令
				__builtin_ia32_pause();
#elif defined(__aarch64__) || defined(__arm__)
				// ARM平台：使用yield指令
				__asm__ __volatile__("yield" ::: "memory");
#else
				// 其他平台：使用标准库让出时间片
				std::this_thread::yield();
#endif
			}
		}
	}

	/*!
	 * \brief 释放锁
	 * 
	 * \details 使用memory_order_release确保：
	 *          - 释放操作对其他线程可见
	 *          - 临界区内的操作不会重排到释放操作之后
	 */
	void unlock()
	{
		flag.store(false, std::memory_order_release);
	}
};

/*!
 * \brief 自旋锁RAII管理器
 * 
 * \details 提供自动锁管理，确保异常安全：
 *          - 构造时自动获取锁
 *          - 析构时自动释放锁
 *          - 禁止拷贝构造和赋值操作
 *          - 遵循RAII原则，异常安全
 */
class SpinLock
{
public:
	/*!
	 * \brief 构造函数，自动获取锁
	 * \param mtx 要管理的自旋锁引用
	 */
	SpinLock(SpinMutex& mtx) :_mutex(mtx) { _mutex.lock(); }
	
	/// 禁止拷贝构造
	SpinLock(const SpinLock&) = delete;
	
	/// 禁止赋值操作
	SpinLock& operator=(const SpinLock&) = delete;
	
	/// 析构函数，自动释放锁
	~SpinLock() { _mutex.unlock(); }

private:
	SpinMutex&	_mutex;	///< 管理的自旋锁引用
};
